﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading;
using SPMS.Utility;
using SPMS.Log.Core;

namespace SPMS.Log.Utility
{
    /// <summary>
    /// 使用互斥体作为同步区域实现的同步上下文
    /// </summary>
    /// <remarks></remarks>
    /// <history>
    /// [zanezeng]               2010/1/14 9:26    创建
    /// </history>
    public sealed class MutexSynchronizationContext : ISynchronizationContext
    {
        #region ---Constructor

        /// <summary>
        /// 初始化类型<see cref="MutexSynchronizationContext"/>的新实例
        /// </summary>
        /// <param name="handle">用于创建同步区域的互斥体</param>
        /// <remarks></remarks>
        /// <exception cref="ArgumentNullException"><paramref name="handle"/>为<c>null</c>引用。</exception>
        /// <history>
        /// [zanezeng]               2010/1/14 9:28    创建
        /// </history>
        public MutexSynchronizationContext( Mutex handle )
            : this( handle, Timeout.Infinite )
        {

        }

        /// <summary>
        /// 初始化类型<see cref="MutexSynchronizationContext"/>的新实例
        /// </summary>
        /// <param name="handle">用于创建同步区域的互斥体</param>
        /// <param name="millisecondsTimeout">创建同步区域的超时时间，单位为毫秒。</param>
        /// <remarks></remarks>
        /// <exception cref="ArgumentNullException"><paramref name="handle"/>为<c>null</c>引用。</exception>
        /// <exception cref="ArgumentOutOfRangeException"><paramref name="millisecondsTimeout"/>小于-1。</exception>
        /// <history>
        /// [zanezeng]               2010/1/14 9:28    创建
        /// </history>
        public MutexSynchronizationContext( Mutex handle, int millisecondsTimeout )
        {
            //断言参数
            ArgumentAssert.AssertArgumentNotNull( handle, "handle" );
            ArgumentAssert.AssertArgumentRange( millisecondsTimeout, Timeout.Infinite, int.MaxValue, "millisecondsTimeout" );

            //保存参数
            this.m_Handle = handle;
            this.m_Timeout = millisecondsTimeout;
        }

        #endregion

        #region ---ISynchronizationContext

        /// <summary>
        /// 根据给定的状态对象创建同步区域
        /// </summary>
        /// <param name="state">用于创建同步区域的状态对象</param>
        /// <returns>同步区域凭证。调用同步区域凭证的Dispose方法，则释放同步区域。</returns>
        /// <remarks></remarks>
        /// <exception cref="TimeoutException">在给定的超时时间内创建同步区域失败。</exception>
        /// <history>
        /// [zanezeng]               2010/1/14 9:05    创建
        /// </history>
        /// <remarks></remarks>
        /// <history>
        /// [zanezeng]               2010/1/14 9:35    创建
        /// </history>
        public IDisposable Synchronize( object state )
        {
            //判断互斥体是否可以创建同步区域
            if (null != this.m_Handle && !this.m_Handle.SafeWaitHandle.IsClosed)
            {
                //等待获得排它锁
                if (!this.m_Handle.WaitOne( this.m_Timeout ))
                {
                    //输出日志
                    if (LoggingContext.MetaLog.IsErrorEnabled)
                    {
                        LoggingContext.MetaLog.Error( "使用互斥体'{0}'为状态对象'{1}'创建同步区域失败", this.m_Handle, state );
                    }

                    //抛出异常
                    throw new TimeoutException( Properties.Resources.MSG_SYNCHRONIZE_TIMEOUT );
                }

                //返回同步区域对象
                return new SynchronizationRegion( this.m_Handle );
            }

            //默认返回空引用
            return null;
        }

        #endregion

        #region ---Field

        /// <summary>
        /// 用于创建同步区域的互斥体
        /// </summary>
        private Mutex m_Handle;

        /// <summary>
        /// 同步区域创建超时时间
        /// </summary>
        private int m_Timeout;

        #endregion

        #region ---Class

        /// <summary>
        /// 同步区域
        /// </summary>
        /// <remarks></remarks>
        /// <history>
        /// [zanezeng]               2010/1/14 9:42    创建
        /// </history>
        private sealed class SynchronizationRegion : IDisposable
        {
            #region ---Constructor

            /// <summary>
            /// 初始化类型<see cref="SynchronizationRegion"/>的新实例
            /// </summary>
            /// <param name="handle">用于创建同步区域的互斥体</param>
            /// <remarks></remarks>
            /// <history>
            /// [zanezeng]               2010/1/14 9:43    创建
            /// </history>
            public SynchronizationRegion( Mutex handle )
            {
                //保存参数
                this.m_Handle = handle;
            }

            #endregion

            #region ---IDisposable

            /// <summary>
            /// 执行与释放或重置非托管资源相关的应用程序定义的任务
            /// </summary>
            /// <remarks></remarks>
            /// <history>
            /// [zanezeng]               2010/1/14 9:44    创建
            /// </history>
            public void Dispose()
            {
                //判断互斥体是否需要释放
                if (null != this.m_Handle && !this.m_Handle.SafeWaitHandle.IsClosed)
                {
                    //释放互斥体
                    this.m_Handle.ReleaseMutex();
                }
            }

            #endregion

            #region ---Field

            /// <summary>
            /// 用于创建同步区域的互斥体
            /// </summary>
            private Mutex m_Handle;

            #endregion
        }

        #endregion
    }
}
